using System;
using System.IO;
using NUnit.Framework;
using Subsync.Core.Subversion;
using Subsync.Core.Sync;

namespace Subsync.Test.UnitTests
{
	/// <summary>
	/// Author: Ruchi and Zhang Andy 
	/// </summary>
	
	[TestFixture()]
	public class SubversionCommands
	{
		private static string testing_folder;
		private static string working_copy;
        private static string working_copy_new;
		private static string repos_path;
		private static string repos_url;
		private static string lock_file;
		private static string new_FileName;
		
		/// <summary>
		/// In this Unit Test, we will test the subversion commands in 
		/// Core/Subversion.
		/// </summary>
		public SubversionCommands() {
			
			testing_folder = Path.Combine(Directory.GetCurrentDirectory(),"unit_test");
			working_copy = Path.Combine(testing_folder,"working_copy");
            working_copy_new = Path.Combine(testing_folder, "working_copy_new");
			repos_path = Path.Combine(testing_folder,"_repos");
            repos_url = string.Concat("file:///", repos_path);
			new_FileName = "a.txt";
            if (Directory.Exists(testing_folder))
			    Directory.Delete(testing_folder, true);
			Directory.CreateDirectory(testing_folder);
			Directory.CreateDirectory(working_copy);
		}
		
		/// <summary>
		/// create a new repository and check if the right files/dir is created.
		/// </summary>
		[Test(Description = "Create a repos")]
		public void _01_SVNAdminCreate()
		{	
			//create the repository
			new SVNAdminCreate(repos_path).Execute();
		
			//check for the repository creation
			
			//check for conf folder
			string conf_folder = Path.Combine(repos_path,"conf");
			Assert.IsTrue(Directory.Exists(conf_folder));
			
			//check for conf/svnserve.conf
			Assert.IsTrue(File.Exists(Path.Combine(conf_folder,"svnserve.conf")));
			
			//check for db folder
			string db_folder = Path.Combine(repos_path,"db");
			Assert.IsTrue(Directory.Exists(db_folder));
			
			//check for db/uuid
			Assert.IsTrue(File.Exists(Path.Combine(db_folder,"uuid")));
			
			//check for hooks folder
			string hooks_folder = Path.Combine(repos_path,"hooks");
			Assert.IsTrue(Directory.Exists(hooks_folder));
			
			//check for locks folder
			string locks_holder = Path.Combine(repos_path,"locks");
			Assert.IsTrue(Directory.Exists(locks_holder));
		}
		
		/// <summary>
		/// checks out a new repository and check if the right folder is created.
		/// </summary>
		[Test()]
		public void _02_SVNCheckout()
		{
			//checkout the repository
			new SVNCheckout(repos_url, working_copy).Execute();
			
			//check status
            SVNStatus status = new SVNStatus(working_copy);
            status.Execute();
            Assert.IsTrue(string.Equals(status.statusInfo.pathChangeType, " "));
		}
		
		/// <summary>
		/// adds a file to the repository and checks if its done correctly
		/// </summary>
		[Test()]
		public void _03_SVNAdd()
		{	
			//combine the new filename with the path
			string new_FilePath = Path.Combine(testing_folder, new_FileName);					
			
			// Create the file and write to it.
			TextWriter ts = new StreamWriter(new_FilePath);
            ts.WriteLine("Testing ");
            ts.Close();
			
			//Move the file to working_copy
			string destination_FilePath = Path.Combine(working_copy, new_FileName);
			
			File.Move(new_FilePath, destination_FilePath);
						
			//add the file to repository 
			new SVNAdd(destination_FilePath, true).Execute();
			
			//commit the working copy	
			new SVNCommit(working_copy).Execute();	
			
			//update the working copy	
			new SVNUpdate(working_copy).Execute();				
			
			//check that file exists
			Assert.IsTrue(File.Exists(destination_FilePath));
			
		}
		
		/// <summary>
		/// reverts to revision 0 and checks if the working_copy is empty
		/// </summary>
		[Test()]
		public void _04_SVNRevert()
		{	
			// Create the file and write to it.
			string destination_FilePath = Path.Combine(working_copy, new_FileName);
			File.Delete(destination_FilePath);
			Assert.IsTrue(!File.Exists(destination_FilePath));
			
			string[] revertpaths = {working_copy};
			//revert
			new SVNRevert(revertpaths).Execute();
			
			//check that file exists
			Assert.IsTrue(File.Exists(destination_FilePath));
		}
		
		/// <summary>
		/// moves a file 
		/// </summary>
		[Test()]
		public void _05_SVNMove()
		{	
			//Create folder to test SVNMove
			string fileOriginal = Path.Combine(working_copy, new_FileName);
			string fileAfterMove = Path.Combine(working_copy, "newname.txt");
			
			//move
			new SVNMove(fileOriginal, fileAfterMove).Execute();
			
			//commit the working copy	
			new SVNCommit(working_copy).Execute();	
			
			//update the working copy	
			new SVNUpdate(working_copy).Execute();	
						
			//check if working_copy directory is empty
			Assert.IsTrue(File.Exists(fileAfterMove));
		}
		
		/// <summary>
		/// removes a file from the repository and checks if its done correctly
		/// </summary>
		[Test()]
		public void _06_SVNRemove()
		{	
			//path of file to remove
			//Move the file to working_copy/dev for the repos_url in this test
			string destination_FilePath = Path.Combine(working_copy,"newname.txt");
						
			// Remove the file
			new SVNRemove(destination_FilePath).Execute();
			
			//commit the working copy	
			new SVNCommit(working_copy).Execute();	
			
			//update the working copy	
			new SVNUpdate(working_copy).Execute();				
			
			//check that file exists
		    Assert.IsTrue(!File.Exists(destination_FilePath));
		
		}
		
		/// <summary>
		/// makes new directory
		/// </summary>
		[Test()]
		public void _07_SVNMkdir()
		{	
			//url of new directory
			//string[] mkdir = {Path.Combine(working_copy, "newdir")};				
			string[] mkdir = {Path.Combine(repos_url, "mydir")};	
			
            // Make new directory
			new SVNMkdir(mkdir, "Making new directory").Execute();
			
			//commit the working copy	
			new SVNCommit(working_copy).Execute();
			
			//update the working copy	
			new SVNUpdate(working_copy).Execute();				
			
			//check that directory exists
            Assert.IsTrue(Directory.Exists(Path.Combine(working_copy, "mydir")));
		}
			
		
		[Test()]
		public void _08_SVNLock()
		{
			//create a file
			lock_file = Path.Combine(working_copy, "lockme.txt");
			TextWriter lockme = new StreamWriter (lock_file);
			lockme.WriteLine("Please lock me, I've been bad.");
			lockme.Close();
			
			//svn add
			new SVNAdd(lock_file, false).Execute();
		
			//commit it
			new SVNCommit(working_copy).Execute();
			
			//lock it
			new SVNLock(lock_file,"Nunit Test Lock").Execute();

            //check status
            SVNStatus status = new SVNStatus(lock_file);
            status.Execute();
            Assert.IsTrue(string.Equals(status.statusInfo.lockLabel, "K"));
		}

		[Test()]
		public void _09_SVNUnlock()
		{
			//unlock file
            new SVNUnlock(lock_file).Execute();
			
			//commit the working copy	
			new SVNCommit(working_copy).Execute();	
			
			//update the working copy	
			new SVNUpdate(working_copy).Execute();			

            //check status
            SVNStatus status = new SVNStatus(lock_file);
            status.Execute();
            Assert.IsTrue(string.Equals(status.statusInfo.lockLabel, " "));
		}
		
		[Test()]
		public void _10_SVNProperties ()
		{
			
			//set porperty
			new SVNPropSet (working_copy, "copyright", "@Subsync").Execute();
			
			//do a status check
            SVNStatus status = new SVNStatus(working_copy);
            status.Execute();
			
            Assert.IsTrue(string.Equals(status.statusInfo.propertiesChangeType, "M"));
			
			//edit porperty
			new SVNPropEdit (working_copy, "copyright", "@CodeJunkies").Execute();	
						
			//do a status check
            status = new SVNStatus(working_copy);
            status.Execute();
			
            Assert.IsTrue(string.Equals(status.statusInfo.propertiesChangeType, "M"));
		}
		
		
		
		/// <summary>
		/// performs an SVN import
		/// </summary>
		[Test()]
		public void _11_SVNImport()
		{
            string test_import = Path.Combine(working_copy, "test_import");
            Directory.CreateDirectory(test_import);
            string test_file = Path.Combine(test_import, "test.txt");
            TextWriter test = new StreamWriter(test_file);
            test.WriteLine("Testing... 1, 2, 3.");
            test.Close();

            string repos_import_url = Path.Combine(repos_url, "test_import");
            //Import new file in a new folder. Repos should create the new folder.
            new SVNImport(test_import, repos_import_url).Execute();

            //Update to check if repos has file.
            new SVNUpdate(working_copy).Execute();

            Assert.IsTrue(File.Exists(test_file));
		}

        /// <summary>
        /// performs an SVN resolve/ status
        /// </summary>
        [Test()]
        public void _12_SVNResolve()
        {
            new SVNCheckout(repos_url, working_copy_new).Execute();
            string test_import_2 = Path.Combine(working_copy_new, "test_import");
            string test_file_2 = Path.Combine(test_import_2, "test.txt");
            string test2_file_2 = Path.Combine(test_import_2, "test2.txt");
            TextWriter wc2 = new StreamWriter(test2_file_2);
            wc2.WriteLine("Testing... 4, 5, 6.");
            wc2.Close();

            File.Replace(test2_file_2, test_file_2, null);

            string test_import = Path.Combine(working_copy, "test_import");
            string test_file = Path.Combine(test_import, "test.txt");
            string test2_file = Path.Combine(test_import, "test2.txt");
            TextWriter wc1 = new StreamWriter(test2_file);
            wc1.WriteLine("Testing... 7, 8, 9.");
            wc1.Close();

            File.Replace(test2_file, test_file, null);

            new SVNCommit(working_copy).Execute();
            
            // Update to create conflict
            new SVNUpdate(working_copy_new).Execute();

            // Check it is in conflicted state.
            SVNStatus status = new SVNStatus(test_file_2);
            status.Execute();
            Assert.IsTrue(string.Equals(status.statusInfo.pathChangeType, "C"));

            // Test resolving
            new SVNResolve(test_file_2, Resolution.TheirsFully).Execute();

            // Read from file
            StreamReader sr = new StreamReader(test_file_2);
            string read = sr.ReadLine();

            Assert.IsTrue(string.Equals(read, "Testing... 7, 8, 9."));
        }
		
		
		
		
	}
}